package com.edu.whty.common.tools;

import com.edu.whty.common.constants.Constant;
import com.edu.whty.common.tools.redis.RedisUtil;
import com.edu.whty.entity.system.SysConfigPo;
import com.edu.whty.service.base.ConfigService;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Component
public class SysConfig {

    private static Logger logger = LoggerFactory.getLogger(SysConfig.class);

    private static Properties properties = new Properties();

    private static final String syscfg = "system.properties";

    @Autowired
    private ConfigService configService;

    @Autowired
	private static RedisUtil redisUtil;

    private static SysConfig sysConfig = null;

    private static Document document = null;

    //过期时间
    public static long expires = Constant.REDIS_DEFAULT_EXPIRES;

    public static final String REDIS_KEY_PREFIX = "sysconfig_";

    /**
     * 平台编码和域名对应表
     */
    //private static Map<String, String> platformCodeDomainMap = new HashMap<String, String>();

    static {
        InputStream sysin = null;
        InputStream xmlin = null;
        try {
            sysin = SysConfig.class.getClassLoader().getResourceAsStream(syscfg);
            properties.load(sysin);

            //加载XML配置
            xmlin = SysConfig.class.getClassLoader().getResourceAsStream("config.xml");
            SAXReader reader = new SAXReader();
            document = reader.read(xmlin);

            logger.info("加载配置'" + syscfg + "'成功！");
        } catch (FileNotFoundException e) {
            logger.error("配置文件不存在！", e);
        } catch (IOException e) {
            logger.error("读取配置文件IO错误！", e);
        } catch (DocumentException e) {
            logger.error("读取XML配置文件错误！", e);
        } finally {

            if (sysin != null) {
                try {
                    sysin.close();
                } catch (IOException e) {
                    logger.error("关闭system.properties文件流异常", e);
                }
            }

            if (xmlin != null) {
                try {
                    xmlin.close();
                } catch (IOException e) {
                    logger.error("关闭config.xml文件流异常", e);
                }
            }
        }

    }

    @PostConstruct
    public void init() {
        sysConfig = this;
        sysConfig.configService = this.configService;
		/*
		try {
			initPlatformCodeDomainMap();
		} catch (Exception e) {
			logger.error("初始化platformCodeDomainMap和cachedKeyList错误，错误信息：" + e.getMessage(), e);
			System.exit(-1);
		}*/
    }

    /**
     * 根据key获得sysConfig.properties中的值
     *
     * @param key
     * @return
     */
    public static String getStrValue(String key) {

        //优先从配置文件取配置
        String value = properties.getProperty(key);
        if (StringUtils.isNotEmpty(value)) {
            return value;
        }

        HttpServletRequest request = null;
        try {
            request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            logger.error("request为null，system.properties里面也无该配置, key:" + key);
        }

        return getStrValue(key, request);
    }

    /**
     * 根据key和request获得缓存中的值
     *
     * @param key
     * @param
     * @return
     */
    public static String getStrValue(String key, HttpServletRequest request) {

        //优先从配置文件取配置
        String value = properties.getProperty(key);
        if (StringUtils.isNotEmpty(value)) {
            return value;
        }

        if (request != null) {
            String loginPlatformCode = (String) request.getAttribute("loginPlatformCode");
            String platformCode = (String) request.getAttribute("platformCode");
            if (StringUtils.isEmpty(loginPlatformCode)) {
                loginPlatformCode = request.getParameter("loginPlatformCode");
            }
            if (StringUtils.isEmpty(platformCode)) {
                platformCode = request.getParameter("platformCode");
            }
            return getStrValue(key, loginPlatformCode, platformCode);
        }

        return properties.getProperty(key);
    }

    /**
     * 根据key和平台编码
     * 获取指定平台编码是配置参数
     *
     * @param key
     * @param platformCode
     * @return
     */
    public static String getStrValue(String key, String platformCode) {

        //优先从配置文件取配置
        String value = properties.getProperty(key);
        if (StringUtils.isNotEmpty(value)) {
            return value;
        }

        if (StringUtils.isNotEmpty(platformCode)) {
            String cachedKey = SysConfig.REDIS_KEY_PREFIX + platformCode + "_" + key;
            try {
                value = redisUtil.get(cachedKey).toString();
                if (StringUtils.isEmpty(value)) {
                    value = sysConfig.configService.queryConfigValue(key, platformCode, null);
                    if (StringUtils.isNotEmpty(value)) {
                        redisUtil.set(cachedKey, value);
                    }
                }
            } catch (Exception e) {
                logger.error("queryConfig error:" + cachedKey, e);
            }
			
			/*String domain = platformCodeDomainMap.get(platformCode);
			if (StringUtils.isEmpty(domain)) {
				//map里面取不到则重新加载platformCodeDomainMap
				logger.warn("map里面取不到重新加载platformCodeDomainMap, platformCode:" + platformCode);
				try {
					initPlatformCodeDomainMap();
				} catch (Exception e) {
					logger.error("初始化platformCodeDomainMap错误",e);
					return null;
				}
				//再获取一次
				domain = platformCodeDomainMap.get(platformCode);
			}
			
			if (StringUtils.isNotEmpty(domain)) {
				try {
					//XMemCached cached = CourseCached.getCached();
					IRedis redisUtil=(IRedis)ApplicationUtil.getBean("redisUtil");
					String cachedKey = domain + "." + key;
					//value = cached.get(cachedKey);
					value=redisUtil.get(cachedKey);
					logger.info("缓存取得属性，cachedKey:" + cachedKey + ", value:" + value);
					if (StringUtils.isNotEmpty(value)) {
						return value;
					} else {
						//获取不到，则从数据库里面获取
						SysConfigPo config = sysConfig.configService.loadSysConfigPo(domain, key);
						if (config != null) {
							//数据库查询得到说明缓存失效或对应的domain已被删除
							//initPlatformCodeDomainMap();
							//更新缓存
							updateConfigCache(domain);
							
							return config.getValue();
						} else {
							logger.error("数据库和属性文件均无该属性，key：" + key + ", platformCode:" + platformCode);
						}
					}
				} catch (Exception e) {
					logger.error("缓存获取" + domain + "." + key + "异常",e);
				}
			} else {
				logger.error(">>>>>>>platformCode[" + platformCode + "]对应的域名不存在！");
			}*/
        } else {
            logger.error("platformCode为空, key：" + key);
        }

        return value;
    }


    /**
     * 根据key和平台编码
     * 获取指定平台编码是配置参数
     *
     * @param key
     * @param platformCode
     * @return
     */
    public static String getStrValue(String key, String loginPlatformCode, String platformCode) {

        //优先从配置文件取配置
        String value = properties.getProperty(key);
        if (StringUtils.isNotEmpty(value)) {
            return value;
        }

        if (StringUtils.isNotEmpty(loginPlatformCode) && StringUtils.isNotEmpty(platformCode)) {
            String cachedKey = SysConfig.REDIS_KEY_PREFIX + platformCode + "_" + loginPlatformCode + "_" + key;
            try {
                value = redisUtil.get(cachedKey).toString();
                if (StringUtils.isEmpty(value)) {
                    value = sysConfig.configService.queryConfigValue(key, platformCode, loginPlatformCode);
                    if (StringUtils.isNotEmpty(value)) {
                        redisUtil.set(cachedKey, value);
                    }
                }
            } catch (Exception e) {
                logger.error("queryConfig error:" + cachedKey, e);
            }
			
			
			/*String domain = platformCodeDomainMap.get(loginPlatformCode+"."+platformCode);
			if (StringUtils.isEmpty(domain)) {
				//map里面取不到则重新加载platformCodeDomainMap
				logger.warn("map里面取不到重新加载platformCodeDomainMap, loginPlatformCode:" + loginPlatformCode);
				try {
					initPlatformCodeDomainMap();
				} catch (Exception e) {
					logger.error("初始化platformCodeDomainMap错误",e);
					return null;
				}
				//再获取一次
				domain = platformCodeDomainMap.get(loginPlatformCode+"."+platformCode);
			}
			
			if (StringUtils.isNotEmpty(domain)) {
				try {
					//XMemCached cached = CourseCached.getCached();
					IRedis redisUtil=(IRedis)ApplicationUtil.getBean("redisUtil");
					String cachedKey = domain + "." + key;
					//value = cached.get(cachedKey);
					value=redisUtil.get(cachedKey);
					logger.info("缓存取得属性，cachedKey:" + cachedKey + ", value:" + value);
					if (StringUtils.isNotEmpty(value)) {
						return value;
					} else {
						//获取不到，则从数据库里面获取
						SysConfigPo config = sysConfig.configService.loadSysConfigPo(domain, key);
						if (config != null) {
							//数据库查询得到说明缓存失效或对应的domain已被删除
							initPlatformCodeDomainMap();
							//更新缓存
							updateConfigCache(domain);
							
							return config.getValue();
						} else {
							logger.error("数据库和属性文件均无该属性，key：" + key + ", loginPlatformCode:" + loginPlatformCode+ ", platformCode:" + platformCode);
						}
					}
				} catch (Exception e) {
					logger.error("缓存获取" + domain + "." + key + "异常",e);
				}
			} else {
				//logger.error(">>>>>>>loginPlatformCode[" + loginPlatformCode + "]对应的域名不存在！");
			}*/
        } else {
            logger.error("loginPlatformCode或者platformCode为空, key：" + key);
        }

        return value;
    }

    public static String getPlatformDomain(String loginPlatformCode, String platformCode) {
        String cachedKey = SysConfig.REDIS_KEY_PREFIX + platformCode + "_" + loginPlatformCode + "_domain";
        String domain;
        try {
            domain = redisUtil.get(cachedKey).toString();
            if (StringUtils.isEmpty(domain)) {
                //redis里面取不到domain则查数据库
                domain = getPlatformDomainByPlatformCode(loginPlatformCode, platformCode);
                if (null != domain && !domain.equals("")) {
                    redisUtil.set(cachedKey, domain, 24 * 60 * 60);
                }
            }
        } catch (Exception e) {
            logger.error("初始化getPlatformDomain错误", e);
            e.printStackTrace();
            return null;
        }
        return domain;
    }

    /**
     * 根据key获得sysConfig.properties中的值,转为int
     *
     * @param key
     * @return
     */
    public static int getIntValue(String key) {
        String value = getStrValue(key);
        try {
            int intValue = Integer.valueOf(value);
            return intValue;
        } catch (Exception e) {
            logger.error("将value:" + value + ",转为int时发生错误", e);
        }
        return -1;
    }

    /**
     * 初始化platformCodeDomainMap
     *
     * @throws Exception
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    private static String getPlatformDomainByPlatformCode(String loginPlatformCode, String platformCode) throws Exception {
        String domain = null;
        if (null != loginPlatformCode) {
            if (null == platformCode || StringUtils.isEmpty(platformCode)) {
                platformCode = loginPlatformCode;
            }
            Map map = new HashMap();
            map.put("platformCode", platformCode);
            map.put("loginPlatformCode", loginPlatformCode);
            domain = sysConfig.configService.queryPlatformDomain(map);
        }
        return domain;
    }

    /**
     * 更新缓存
     *
     * @throws Exception
     */
    private static void updateConfigCache(String domain) throws Exception {

        Map<String, Object> paramMap = new HashMap<String, Object>();
        if (StringUtils.isNotEmpty(domain)) {
            paramMap.put("domain", domain);
        }
        List<SysConfigPo> configList = sysConfig.configService.listSysConfig(paramMap);
        if (configList == null || configList.isEmpty()) {
            logger.warn("更新配置缓存时，未加载到多平台配置参数！domain:" + domain);
            return;
        }

        //缓存配置
        for (SysConfigPo sysc : configList) {
            String key = sysc.getDomain() + "." + sysc.getKeyName();
            //CourseCached.getCached().put(key, sysc.getValue());
            redisUtil.set(key, sysc.getValue(), expires);
            //logger.info(">>>>>> [缓存多平台配置]，key:" + key + ", value:" + sysc.getValue());
        }
        logger.info(">>>>>> [缓存多平台配置结束] >>>>>>");
    }

    /**
     * 根据key获得sysConfig.properties中的值
     *
     * @param
     * @return
     */
    public static String zxksDataSourceUser() {
        return properties.getProperty("zxksDataSourceUser");
    }

    /**
     * 按名称获取config.xml里面的多个配置
     *
     * @param name
     * @return
     */
    public static List<String> getXmlConfigList(String name) {

        List<String> list = new ArrayList<String>();

        Element root = document.getRootElement();
        for (Object object : root.elements("config")) {
            Element config = (Element) object;
            String configName = config.element("name").getText();
            if (name.equals(configName)) {
                for (Object valueObj : config.elements("value")) {
                    Element value = (Element) valueObj;
                    list.add(value.getText());
                }
            }
        }

        return list;
    }

    public static void main(String[] args) {
        logger.debug(SysConfig.getStrValue("smsListBatchSrcId"));
    }

}
